package com.xbongbong.pro.statistic.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.enums.bi.ChartSourceEnum;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.errorcodes.StatisticsServicesErrorCodeEnum;
import com.xbongbong.pro.enums.permission.enums.ChartProPermissionAliasEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.StatisticsTypeEnum;
import com.xbongbong.pro.statistic.pojo.ChartLinkagePojo;
import com.xbongbong.pro.statistic.pojo.LinkageListParamPojo;
import com.xbongbong.pro.statistic.pojo.LinkageListPojo;
import com.xbongbong.pro.statistic.pojo.SlaveSourcePojo;
import com.xbongbong.pro.statistic.service.ChartLimitService;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 图表联动帮助类
 *
 * @author zyy
 * @date 2022/11/30/ 15:22:00
 * @since v1.0
 */
@Component
public class LinkageHelp {
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private ChartLimitService chartLimitService;
    @Resource
    private CustomHelp customHelp;


    /**
     * 是否满足联动操作的校验
     *
     * @param corpid 公司唯一标识
     * @param chartType 图表type
     * @param statisticsType 图表类型 1-系统图表 2-自定义图表
     * @param permSet 角色权限容器
     * @return boolean true-有权限  false-无权限
     * @author zyy
     * @date 2022/11/30
     * @version v1.0
     */
    public boolean linkageFlag(String corpid, Integer chartType, Integer statisticsType, Set<String> permSet) throws XbbException {
        if(linkageBaseFilter(permSet,corpid)){
            //通用校验没通过直接返回false
            return false;
        }
        //非自定义图表
        if(!Objects.equals(statisticsType,StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())){
            return false;
        }
        return ChartTypeEnum.linkageChartTypeList().contains(chartType);
    }


    /**
     * 联动通用校验
     *
     * @param permSet 用户权限数组
     * @param corpid 公司位置标识
     * @return boolean true-需要过滤  false-不过滤
     * @author zyy
     * @date 2022/12/5
     * @version v1.0
     */
    public boolean linkageBaseFilter(Set<String> permSet, String corpid) throws XbbException {
        //角色不包含联动权限
        if(!permSet.contains(ProPermissionAliasEnum.CHART_LINKAGE.getAlias())){
            return true;
        }
        //非旗舰版公司
        if(!Objects.equals(PackageTypeEnum.ULTIMATE.getType(),packageHelp.getFeeType(corpid))){
            return true;
        }
        //是否ck环境
        return !chartLimitService.getCkFlag();
    }

    /**
     * 获取可见列表中是否可选的图表
     *
     * @param currentChart  联动图表实体
     * @param chartList 可见图表数组
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.LinkageListPojo>
     * @author zyy
     * @date 2022/12/1
     * @version v1.0
     */
    public List<LinkageListPojo> validChartList(ChartEntity currentChart, List<ChartEntity> chartList) {
        //避免对源数据造成影响,下述逻辑都使用拷贝的数据
        List<ChartEntity> canSeeChartList = new ArrayList<>(chartList);
        Integer single = currentChart.getSingle();

        if(ChartSourceEnum.isDataSet(single)){
            //比较数据集id
            return compareDsSource(currentChart,canSeeChartList);
        }

        //非数据集需要通过muti来判断单表、多表
        List<LinkageListPojo> linkageListPojoList = new ArrayList<>();
        ChartSourceEnum chartSourceEnum = EsUtil.getSingle(currentChart) ? ChartSourceEnum.ONE_TABLE : ChartSourceEnum.MUTI_TABLE;
        switch (chartSourceEnum){
            case ONE_TABLE:
                //单表
                linkageListPojoList = compareOneSource(currentChart,canSeeChartList);
                break;
            case MUTI_TABLE:
                //多表
                linkageListPojoList = compareMultiSource(currentChart,canSeeChartList);
                break;
            default:
                break;
        }

        return linkageListPojoList;
    }

    /**
     * 联动图表数据源为`多表`时获取可选图表
     *
     * @param currentChart 联动图表实体
     * @param canSeeChartList 可见图表数组
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.LinkageListPojo>
     * @author zyy
     * @date 2022/12/1
     * @version v1.0
     */
    private List<LinkageListPojo> compareMultiSource(ChartEntity currentChart, List<ChartEntity> canSeeChartList) {
        List<LinkageListPojo> canChooseChartList = new ArrayList<>();
        if(CollectionUtils.isEmpty(canSeeChartList)){
            return canChooseChartList;
        }

        //获取当前联动图表的每个数据源的formId
        List<Long> curChartIdList = getChartAllSourceFormIds(currentChart);

        //过滤不可选图表
        List<ChartEntity> sameSourceChartList = new ArrayList<>();
        for (ChartEntity chartEntity : canSeeChartList) {
            //非多数据源的直接过滤
            if(EsUtil.getSingle(chartEntity)){
                continue;
            }
            List<Long> formIdList = getChartAllSourceFormIds(chartEntity);
            if(new HashSet<>(formIdList).containsAll(curChartIdList)){
                sameSourceChartList.add(chartEntity);
            }
        }

        //数据格式转换
        canChooseChartList = LinkageListPojo.linkageDataFormat(sameSourceChartList);
        //处理图表是否已选
        linkageCheckFlag(currentChart,canChooseChartList);
        return canChooseChartList;
    }

    /**
     * 获取图表所有数据源的formId
     *
     * @param chartEntity 图表实体
     * @return java.util.List<java.lang.Long>
     * @author zyy
     * @date 2022/12/1
     * @version v1.0
     */
    private List<Long> getChartAllSourceFormIds(ChartEntity chartEntity ) {
        //从表formId数组
        JSONArray slaveSourceArray = chartEntity.getSlaveSources();
        List<SlaveSourcePojo> slaveSourceList = slaveSourceArray.toJavaList(SlaveSourcePojo.class);
        List<Long> formIdList = slaveSourceList.stream().map(SlaveSourcePojo::getFormId).collect(Collectors.toList());
        //主表formId
        JSONObject driverSource = chartEntity.getDriverSources();
        formIdList.add(driverSource.getLong(XbbConstant.FORM_ID));
        return formIdList;
    }

    /**
     * 联动图表数据源为`单表`时获取可选图表
     *
     * @param currentChart 联动图表实体
     * @param canSeeChartList  被联动图表数组
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.LinkageListPojo>
     * @author zyy
     * @date 2022/12/1
     * @version v1.0
     */
    public List<LinkageListPojo> compareOneSource(ChartEntity currentChart, List<ChartEntity> canSeeChartList) {
        List<LinkageListPojo> canChooseChartList = new ArrayList<>();
        if(CollectionUtils.isEmpty(canSeeChartList)){
            return canChooseChartList;
        }

        //获取联动图表的数据源
        JSONObject driverSources = currentChart.getDriverSources();
        Long curFormId = driverSources.getLong(XbbConstant.FORM_ID);
        List<ChartEntity> sameSourceChartList = new ArrayList<>();
        canSeeChartList.forEach(chartEntity -> {
            //根据可见图表数据源类型，做不同的过滤
            ChartSourceEnum chartSourceEnum = ChartSourceEnum.getChartSource(chartEntity.getSingle(), chartEntity.getMuti());
            switch (chartSourceEnum){
                case ONE_TABLE:
                    //单表对比formId
                    if(sameOneSource(chartEntity,curFormId,XbbConstant.FORM_ID)){
                        sameSourceChartList.add(chartEntity);
                    }
                    break;
                case MUTI_TABLE:
                    //多表比较所有数据源的formId
                    List<Long> chartAllSourceFormIds = getChartAllSourceFormIds(chartEntity);
                    if(chartAllSourceFormIds.contains(curFormId)){
                        sameSourceChartList.add(chartEntity);
                    }
                    break;
                default:
                    //数据集直接忽略
                    break;
            }
        });

        //数据格式转换
        canChooseChartList = LinkageListPojo.linkageDataFormat(sameSourceChartList);
        //处理图表是否已选
        linkageCheckFlag(currentChart,canChooseChartList);
        return canChooseChartList;
    }

    /**
     * 一个数据源的图表是否相同
     *
     * @param chartEntity 被联动图表的实体
     * @param curValue 联动图表的字段值
     * @param key 对比字段的名称
     * @return boolean
     * @author zyy
     * @date 2022/12/1
     * @version v1.0
     */
    private boolean sameOneSource(ChartEntity chartEntity, Long curValue, String key) {
        return Objects.equals(chartEntity.getDriverSources().getLong(key),curValue);
    }


    /**
     * 联动图表数据源为`数据集`时获取可选图表
     *
     * @param currentChart
     * @param canSeeChartList
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.LinkageListPojo>
     * @author zyy
     * @date 2022/12/1
     * @version v1.0
     */
    public List<LinkageListPojo> compareDsSource(ChartEntity currentChart, List<ChartEntity> canSeeChartList) {
        List<LinkageListPojo> canChooseChartList = new ArrayList<>();
        if(CollectionUtils.isEmpty(canSeeChartList)){
            return canChooseChartList;
        }

        //获取相同数据源的图表
        JSONObject driverSources = currentChart.getDriverSources();
        Long dataSetId = driverSources.getLong(XbbConstant.DATA_SET_ID);
        List<ChartEntity> sameSourceChartList = canSeeChartList.stream().filter(chartEntity -> sameOneSource(chartEntity,dataSetId,XbbConstant.DATA_SET_ID)).collect(Collectors.toList());

        //数据格式转换
        canChooseChartList = LinkageListPojo.linkageDataFormat(sameSourceChartList);

        //处理图表是否已选
        linkageCheckFlag(currentChart,canChooseChartList);
        return canChooseChartList;
    }

    /**
     * 被联动图表是否已被选择
     *
     * @param currentChart 联动图表
     * @param canChooseChartList 可被联动图表数组
     * @author zyy
     * @date 2022/12/5
     * @version v1.0
     */
    private void linkageCheckFlag(ChartEntity currentChart, List<LinkageListPojo> canChooseChartList) {
        JSONArray chartLinkage = currentChart.getChartLinkage();
        if(CollectionsUtil.isEmpty(chartLinkage)){
            //无联动选信息则直接返回，字段默认为false，
            return;
        }
        List<ChartLinkagePojo> chartLinkagePojoList = chartLinkage.toJavaList(ChartLinkagePojo.class);
        List<Long> chartIds = chartLinkagePojoList.stream().map(ChartLinkagePojo::getId).collect(Collectors.toList());
        canChooseChartList.forEach(linkageListPojo -> {
            if(chartIds.contains(linkageListPojo.getId())){
                linkageListPojo.setChecked(Boolean.TRUE);
            }
        });
    }

    /**
     * 获取不可选联动图表数组
     *
     * @param chartList 源数组
     * @param validChartList  可选图表数组
     * @return java.util.List<com.xbongbong.pro.statistic.pojo.LinkageListPojo>
     * @author zyy
     * @date 2022/12/5
     * @version v1.0
     */
    public List<LinkageListPojo> invalidChartList(List<ChartEntity> chartList, List<LinkageListPojo> validChartList) {
        //获取可选的图表id
        List<Long> validChartIds = validChartList.stream().map(LinkageListPojo::getId).collect(Collectors.toList());

        //避免对源数据造成影响
        List<ChartEntity> allChartList = new ArrayList<>(chartList);

        //过滤可选的图表
        allChartList.removeIf(chartEntity -> validChartIds.contains(chartEntity.getId()));

        //数据格式转化
        return LinkageListPojo.linkageDataFormat(allChartList);
    }

    /**
     * 获取联动设置中的可见图表
     *
     * @param listParamPojo
     * @return java.util.List<com.xbongbong.pro.domain.entity.ChartEntity>
     * @author zyy
     * @date 2023/1/11
     * @version v1.0
     */
    public List<ChartEntity> canSeeChartByLinkage(LinkageListParamPojo listParamPojo) throws XbbException {
        ChartEntity currentChart = listParamPojo.getChartEntity();
        List<ChartEntity> chartList = listParamPojo.getChartList();
        //校验当前联动图表
        if(Objects.isNull(currentChart)){
            throw new XbbException(StatisticsServicesErrorCodeEnum.API_ERROR_224093);
        }
        chartList.remove(currentChart);

        return chartList.stream()
                //过滤不可见图表
                .filter(chartEntity -> customHelp.isChartPermissions(chartEntity.getPermissions(),
                        listParamPojo.getBaseDTO(),
                        listParamPojo.getOverAllPermissions(),
                        listParamPojo.getSubDepIdMap()).containsKey(ChartProPermissionAliasEnum.CHART_VIEW.getAlias()))
                //过滤非自定义图表
                .filter(chartEntity -> Objects.equals(StatisticsTypeEnum.CUSTOM_STATISTIC.getCode(),chartEntity.getStatisticsType()))
                //过滤不支持的被联动图表类型
                .filter(chartEntity -> ChartTypeEnum.linkedChartTypeList().contains(chartEntity.getChartType()))
                .collect(Collectors.toList());
    }

    /**
     * 实时判断图表是否进行了联动设置
     *
     * @param listParamPojo
     * @return boolean  true-设置  false-未设置
     * @author zyy
     * @date 2023/1/11
     * @version v1.0
     */
    public boolean checkLinkageConfigRealTime(LinkageListParamPojo listParamPojo) throws XbbException {
        ChartEntity chartEntity = listParamPojo.getChartEntity();

        //获取当前分类下可见图表数据
        List<ChartEntity> canSeeChart = canSeeChartByLinkage(listParamPojo);
        //获取可以选的被联动图表
        List<LinkageListPojo> validChartList = validChartList(chartEntity, canSeeChart);

        //获取已经设置的被联动图表
        List<LinkageListPojo> checkChartIdList = validChartList.stream().filter(LinkageListPojo::getChecked).collect(Collectors.toList());
        return CollectionsUtil.isNotEmpty(checkChartIdList);
    }
}
